//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.TridentModel
{
    #region Using directives
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ER = Microsoft.Research.DataLayer;
    using System.Collections.ObjectModel;
    using Microsoft.Research.eResearch.Common.Linq;
    #endregion

    /// <summary>
    /// This class holds the metadata information of an activity.
    /// </summary>
    public class ActivityMetadata
    {
        #region Private members

        /// <summary>
        /// Type of the activity.
        /// </summary>
        private string activityClass;

        /// <summary>
        /// Unique ID of the activity in the Workflow.
        /// </summary>
        private Guid id;

        /// <summary>
        /// Friendly name of the activity.
        /// </summary>
        private string name;

        /// <summary>
        /// Activity Label.
        /// </summary>
        private string label;

        /// <summary>
        /// Description of the Activity.
        /// </summary>
        private string description;

        /// <summary>
        /// Specifies whether the activity is of type Composite or not.
        /// </summary>
        private ER.ActivityType typeOfActivity;

        /// <summary>
        /// List of input parameters.
        /// </summary>
        private Collection<ParameterDescriptionModel> inputParams = new Collection<ParameterDescriptionModel>();

        /// <summary>
        /// List of output parameters.
        /// </summary>
        private Collection<ParameterDescriptionModel> outputParams = new Collection<ParameterDescriptionModel>();

        /// <summary>
        /// Whether BuiltIn Model.
        /// </summary>
        private bool isBuiltIn;

        /// <summary>
        /// Holds the flag which specifies whether the activity needs to hide/display in Activity tree  
        /// </summary>
        private bool isHidden;

        /// <summary>
        /// Holds the flag which specifies whether the activity has been deleted or not
        /// </summary>
        private bool isDeleted;

        /// <summary>
        /// If the activity is composite.
        /// </summary>
        private bool isComposite;

        /// <summary>
        /// Associated assemblies.
        /// </summary>
        private Collection<AssemblyInfoModel> associatedAssemblies = new Collection<AssemblyInfoModel>();

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="activity">source activity object</param>
        public ActivityMetadata(ER.Activity activity)
        {
            #region Validation of Arguments
            if (null == activity)
            {
                throw new ArgumentNullException("activity");
            }
            #endregion

            if (activity != null)
            {
                this.id = ((ER.IObject)activity).ID;

                // Set Class of the activity.
                this.activityClass = activity.ActivityClass;

                // Set Name of the activity.
                this.name = activity.Name;

                // Set Description of the activity.
                this.description = activity.Description;

                // Set Label of the activity.
                this.label = activity.Label;

                // Set Type of activity.
                this.typeOfActivity = activity.Type;

                // Set whether the activity is BuiltIn.
                this.isBuiltIn = activity.IsBuiltIn;

                // Set whether the activity need to be displayed / hidden
                this.isHidden = activity.IsHidden;

                // Set whether the activity is Deleted
                this.isDeleted = activity.IsDeleted;

                // Set whether the activity is composite.
                this.isComposite = activity.IsComposite;

                // Set whether the activity is Condition Activity.
                this.IsConditionActivity = activity.IsCondition;

                // Set the display label of Condition Activity.
                this.DisplayLabel = activity.DisplayLabel;

                // Check if an update is available.
                ER.Activity latestActivity = ActivityMetadata.CheckIfUpdateAvailable(activity);
                if (latestActivity != null)
                {
                    this.UpdateAvailable = true;
                    this.LatestEntityId = (latestActivity as ER.IObject).ID;
                }

                // Set the version.
                this.Version = activity.Version;

                if (activity.AssemblyPackages.Count > 0)
                {
                    // Maintain the assembly information.
                    activity.AssemblyPackages[0].AssemblyImages
                        .ForEach(assemblyImage => this.associatedAssemblies
                            .Add(new AssemblyInfoModel() { AssemblyFullName = assemblyImage.Filename, IsActivityDll = assemblyImage.IsActivityDll, AssemblyChecksum = assemblyImage.Checksum }));
                }

                // Set the parameters in the activity.
                this.InitParamMetadata(activity);
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the Type of the activity that this model pertains to.
        /// </summary>
        public string ActivityClass
        {
            get
            {
                return this.activityClass;
            }
        }

        /// <summary>
        /// Gets the unique name of the activity in the workflow model pertains to.
        /// </summary>
        public Guid Id
        {
            get
            {
                return this.id;
            }
        }

        /// <summary>
        /// Geta a human readable workflowName identifying the activity.
        /// </summary>
        public string Name
        {
            get
            {
                return this.name;
            }
        }

        /// <summary>
        /// Gets a workflowName particularly relevant to a design tool working with this activity.
        /// This property will fall back to Name if no label was ever specified.
        /// </summary>
        public string Label
        {
            get
            {
                return this.label;
            }
        }

        /// <summary>
        /// Gets the description of Activity.
        /// </summary>
        public string Description
        {
            get
            {
                return this.description;
            }
        }

        /// <summary>
        /// Gets Type of Activity based on registry (Ex. Root, Leaf, Sequence).
        /// </summary>
        public ER.ActivityType TypeOfActivity
        {
            get
            {
                return this.typeOfActivity;
            }
        }

        /// <summary>
        /// Gets the models for the input parameters.
        /// </summary>
        public Collection<ParameterDescriptionModel> InputParameters
        {
            get
            {
                return this.inputParams;
            }
        }

        /// <summary>
        /// Gets the models for the output parameters.
        /// </summary>
        public Collection<ParameterDescriptionModel> OutputParameters
        {
            get
            {
                return this.outputParams;
            }
        }

        /// <summary>
        /// Gets whether the Activity is of Built In Type.
        /// </summary>
        public bool IsBuiltIn
        {
            get
            {
                return this.isBuiltIn;
            }
        }

        /// <summary>
        /// Gets whether the Activity need to be displayed/hidden.
        /// </summary>
        public bool IsHidden
        {
            get
            {
                return this.isHidden;
            }
        }

        /// <summary>
        /// Gets whether the Activity deleted or not.
        /// </summary>
        public bool IsDeleted
        {
            get
            {
                return this.isDeleted;
            }
        }

        /// <summary>
        /// Gets or sets if the activity is composite.
        /// </summary>
        public bool IsComposite
        {
            get
            {
                return this.isComposite;
            }
        }

        /// <summary>
        /// Gets or sets the latest entity id.
        /// </summary>
        /// <value>The latest entity id.</value>
        public virtual Guid LatestEntityId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether new version available.
        /// </summary>
        /// <value><c>true</c> if new version available; otherwise, <c>false</c>.</value>
        public bool UpdateAvailable
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the version.
        /// </summary>
        /// <value>The version.</value>
        public int Version
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is condition activity.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is condition activity; otherwise, <c>false</c>.
        /// </value>
        public bool IsConditionActivity { get; private set; }

        /// <summary>
        /// Gets or sets the display label.
        /// </summary>
        /// <value>The display label.</value>
        public string DisplayLabel { get; private set; }

        /// <summary>
        /// Gets the associated assemblies.
        /// </summary>
        /// <value>The associated assemblies.</value>
        public Collection<AssemblyInfoModel> AssociatedAssemblies
        {
            get
            {
                return this.associatedAssemblies;
            }
        }

        #endregion

        #region Private methods

        /// <summary>
        /// This is used to initialize the Paramaeter description Model.
        /// </summary>
        /// <param name="erActivitySequence">ActivitySequence for which the model has to be created.</param>
        private void InitParamMetadata(ER.Activity activity)
        {
            // Get and set all the property metadata in the Activity.
            foreach (ER.ActivityParameter param in activity.ActivityParameters)
            {
                ParameterDescriptionModel paramModel = new ParameterDescriptionModel(param);

                if (paramModel.IsInputParameter)
                {
                    // Input Parameter.
                    this.inputParams.Add(paramModel);
                }
                else
                {
                    // Output Parameter.
                    this.outputParams.Add(paramModel);
                }
            }
        }

        /// <summary>
        /// Checks if update available.
        /// </summary>
        /// <param name="activity">The activity.</param>
        /// <returns></returns>
        private static ER.Activity CheckIfUpdateAvailable(ER.Activity activity)
        {
            ER.Activity latestActivity = null;
            if (activity != null && !activity.IsLatestVersion())
            {
                latestActivity = activity.GetLatestActivity();
            }

            return latestActivity;
        }

        #endregion
    }
}
